using System;
using NUnit.Framework;
using Tycho.Parser.Peg;

namespace Tycho.Parser.Tests.Peg
{
    [TestFixture]
    public class IndentationProductionSpecification
    {
        [Test]
        public void ShouldReturnIndentationForNewLine () {
            AssertIndentation ("\n   id", "   ", 1);
            AssertIndentation ("\r\n   id", "   ", 2);
            AssertIndentation ("  \n   id", "   ", 3);
            AssertIndentation ("  \r\n   id", "   ", 4);
            AssertIndentation ("  \n  \n id", " ", 6);
            AssertIndentation ("  \r\n  \r\n id", " ", 8);
            AssertIndentation ("  \nid", "", 3);
            AssertIndentation ("  \r\nid", "", 4);
        }

        [Test]
        public void ShouldReturnNullIndentIfEndOfSource () {
            AssertNoIndent ("\n   ");
            AssertNoIndent ("\r\n   ");
            AssertNoIndent ("  \n   ");
            AssertNoIndent ("  \r\n   ");
            AssertNoIndent ("  \n  \n ");
            AssertNoIndent ("  \r\n  \r\n ");
            AssertNoIndent ("  \n");
            AssertNoIndent ("  \r\n");
        }

        [Test]
        public void ShouldNotParseAtAll () {
            AssertNotParsed ("");
            AssertNotParsed ("id");
            AssertNotParsed ("8");
            AssertNotParsed ("  9\n");
        }

        private static void AssertNotParsed (string source) {
            var indentation = new IndentationProduction ();
            var result = indentation.Parse (source);

            Assert.That (result, Is.Null);
        }

        private static void AssertNoIndent (string source) {
            var indentation = new IndentationProduction ();
            var result = indentation.Parse (source);

            Assert.That (result, Is.Not.Null);
            Assert.That (result.Index, Is.EqualTo (source.Length));
            var term = result.Term as IndentationTerm;
            Assert.That (term, Is.Not.Null);
            Assert.That (term.Indent, Is.Null);
            Assert.That (term.SourceInformation, Is.EqualTo (new SourceInformation (null, 0, source.Length)));
        }

        private static void AssertIndentation (string source, string expectedIndent, int expectedStartIndex) {
            var indentation = new IndentationProduction ();
            var result = indentation.Parse (source);

            Assert.That (result, Is.Not.Null);
            Assert.That (result.Index, Is.EqualTo (expectedStartIndex + expectedIndent.Length));
            Assert.That (result.Context.LastIndent, Is.EqualTo (expectedIndent));
            var term = result.Term as IndentationTerm;
            Assert.That (term, Is.Not.Null);
            Assert.That (term.Indent, Is.EqualTo (expectedIndent));
            Assert.That (term.SourceInformation, Is.EqualTo (new SourceInformation (null, 0, expectedIndent.Length + expectedStartIndex)));
        }
    }
}